uniform vec3 headPos;
uniform vec3 neckPos;
uniform vec3 torsoPos;
uniform vec3 rShoulderPos;
uniform vec3 lShoulderPos;
uniform vec3 rElbowPos;
uniform vec3 lElbowPos;
uniform vec3 rHandPos;
uniform vec3 lHandPos;
uniform vec3 rHipPos;
uniform vec3 lHipPos;
uniform vec3 rKneePos;
uniform vec3 lKneePos;
uniform vec3 rFootPos;
uniform vec3 lFootPos;

uniform float dt;
varying vec3 eyeNormal;
varying vec3 eyePosition;

uniform sampler2D baseMap;
uniform sampler2D jointTexture;

mat4 getZRot(vec2 a, vec2 b, int n) {
	float theta = acos(dot(a,b)/(length(a)*length(b)));
	mat4 zRot = mat4(
		cos(theta), 	-n*sin(theta), 	0, 	0,
		n*sin(theta), 	cos(theta), 	0, 	0,
		0,				0,				1,	0,
		0,				0,				0,	1
	);
	return zRot;
}

mat4 getYRot(vec2 c, vec2 d, int n) {
	float phi = acos(dot(c,d)/(length(c)*length(d)));	
	mat4 yRot = mat4(
		cos(phi), 		0, 		n*sin(phi), 0,
		0, 				1, 		0, 			0,
		-n*sin(phi),	0,		cos(phi),	0,
		0,				0,		0,			1
	);
	return yRot;
}

mat4 getXRot(vec2 e, vec2 f, int n) {
	float chi = acos(dot(e,f)/(length(e)*length(f)));	
	mat4 xRot = mat4(
		1, 	0, 				0, 				0,
		0, 	cos(chi), 		-n*sin(chi), 	0,
		0,	n*sin(chi),		cos(chi),		0,
		0,	0,				0,				1
	);
	return xRot;
}

mat4 getLimbZRot(vec4 secondJointOrigin, vec4 firstJointDispl, vec4 firstJointOrigin, vec4 secondJointDispl, int n) {
	vec2 a = (secondJointOrigin.xy) - (firstJointOrigin.xy);
	vec2 b = (secondJointOrigin.xy + secondJointDispl.xy) - (firstJointOrigin.xy + firstJointDispl.xy);
	mat4 zRot = getZRot(a, b, n);
	return zRot;
}

mat4 getLimbYRot(vec4 secondJointOrigin, vec4 firstJointDispl, vec4 firstJointOrigin, vec4 secondJointDispl, int n) {
	vec2 c = (secondJointOrigin.zx) - (firstJointOrigin.zx);
	vec2 d = (secondJointOrigin.zx + secondJointDispl.zx) - (firstJointOrigin.zx + firstJointDispl.zx);
	mat4 yRot = getYRot(c, d, n);
	return yRot;
}

mat4 getLimbXRot(vec4 secondJointOrigin, vec4 firstJointDispl, vec4 firstJointOrigin, vec4 secondJointDispl, int n) {
	vec2 e = (secondJointOrigin.zy) - (firstJointOrigin.zy);
	vec2 f = (secondJointOrigin.zy + secondJointDispl.zy) - (firstJointOrigin.zy + firstJointDispl.zy);
	mat4 xRot = getXRot(e, f, n);
	return xRot;
}


void main() {  
    vec4 vertex;    
    vec3 normal;    

    vertex = gl_Vertex;  
    normal = gl_Normal;  

	vec4 neckWorldOrigin = vec4(0.0,1.65,0.0,1.0);
	vec4 lShoulderWorldOrigin = vec4(0.2, 1.45, -0.03, 1.0);
	vec4 rShoulderWorldOrigin = vec4(-0.2, 1.45, -0.03, 1.0);
	vec4 lElbowWorldOrigin = vec4(0.5, 1.42, -0.03, 1.0);
	vec4 rElbowWorldOrigin = vec4(-0.5, 1.42, -0.03, 1.0);
	vec4 lHipWorldOrigin = vec4(0.1, 0.85, -0.03, 1.0);
	vec4 lKneeWorldOrigin = vec4(0.13, 0.45, -0.03, 1.0);
	vec4 rHipWorldOrigin = vec4(-0.1, 0.85, -0.03, 1.0);
	vec4 rKneeWorldOrigin = vec4(-0.13, 0.45, -0.03, 1.0);
	
	vec4 headOrigin = vec4(0.061153, -0.538794, 2.350367, 1.0);
	vec4 headDispl = vec4(headPos, 1.0) - headOrigin;
	
	vec4 neckOrigin = vec4(0.066487, -0.724436, 2.339861, 1.0);
	vec4 neckDispl = vec4(neckPos, 1.0) - neckOrigin;
	
	vec4 torsoOrigin = vec4(0.071133, -0.917302, 2.324341, 1.0);
	vec4 torsoDispl = vec4(torsoPos, 1.0) - torsoOrigin;
	
	vec4 rShoulderOrigin = vec4(0.202404, -0.720113, 2.326764, 1.0);
	vec4 rShoulderDispl = vec4(rShoulderPos, 1.0) - rShoulderOrigin;
	
	vec4 lShoulderOrigin = vec4(-0.069431, -0.728760, 2.352959, 1.0);
	vec4 lShoulderDispl = vec4(lShoulderPos, 1.0) - lShoulderOrigin;
	
	vec4 rElbowOrigin = vec4(0.464606, -0.712071, 2.307670, 1.0);
	vec4 rElbowDispl = vec4(rElbowPos, 1.0) - rElbowOrigin;
	
	vec4 lElbowOrigin = vec4(-0.315874, -0.724174, 2.357194, 1.0);
	vec4 lElbowDispl = vec4(lElbowPos, 1.0) - lElbowOrigin;
	
	vec4 rHandOrigin = vec4(0.711478, -0.735119, 2.257507, 1.0);
	vec4 rHandDispl = vec4(rHandPos, 1.0) - rHandOrigin;
	
	vec4 lHandOrigin = vec4(-0.581898, -0.777892, 2.279048, 1.0);
	vec4 lHandDispl = vec4(lHandPos, 1.0) - lHandOrigin;
	
	vec4 rHipOrigin = vec4(0.164691, -1.109141, 2.302899, 1.0);
	vec4 rHipDispl = vec4(rHipPos, 1.0) - rHipOrigin;
	
	vec4 lHipOrigin = vec4(-0.013078, -1.114582, 2.320196, 1.0);
	vec4 lHipDispl = vec4(lHipPos, 1.0) - lHipOrigin;
	
	vec4 rKneeOrigin = vec4(0.180626, -1.482232, 2.201119, 1.0);
	vec4 rKneeDispl = vec4(rKneePos, 1.0) - rKneeOrigin;
	
	vec4 lKneeOrigin = vec4(-0.046642, -1.486995, 2.219973, 1.0);
	vec4 lKneeDispl = vec4(lKneePos, 1.0) - lKneeOrigin;
	
	vec4 rFootOrigin = vec4(0.190280, -1.790680, 2.174107, 1.0);
	vec4 rFootDispl = vec4(rFootPos, 1.0) - rFootOrigin;
	
	vec4 lFootOrigin = vec4(-0.048608, -1.771473, 2.193910, 1.0);
	vec4 lFootDispl = vec4(lFootPos, 1.0) - lFootOrigin;
	
	vec3 baseMapColor = texture2D (jointTexture,gl_MultiTexCoord0.st).rgb;
 
	vertex = (vertex + torsoDispl);
	
	// head rotation
	if(baseMapColor == vec3(0.0,0.0,1.0)) {
	
		mat4 zRot = getLimbZRot(headOrigin, neckDispl, neckOrigin, headDispl, headPos.x > headOrigin.x ? 1 : -1);
		
		vertex = zRot * (vertex - neckWorldOrigin);
		vertex = (vertex + neckWorldOrigin);
	
	} 
	
	// rElbow rotation
	if(baseMapColor == vec3(0.2,0.2,0.0)) {
		mat4 zRot = getLimbZRot(rElbowOrigin, rShoulderDispl, rShoulderOrigin, rElbowDispl, rElbowPos.y > rElbowOrigin.y ? 1 : -1);
		mat4 yRot = getLimbYRot(rElbowOrigin, rShoulderDispl, rShoulderOrigin, rElbowDispl, rElbowPos.z > rElbowOrigin.z ? 1 : -1);
		
		vertex = yRot * zRot * (vertex - rShoulderWorldOrigin);
		vertex = (vertex + rShoulderWorldOrigin);
	} 
	
	// lElbow rotation
	if(baseMapColor == vec3(1.0,1.0,0.0)) {
		mat4 zRot = getLimbZRot(lElbowOrigin, lShoulderDispl, lShoulderOrigin, lElbowDispl, lElbowPos.y > lElbowOrigin.y ? -1 : 1);
		mat4 yRot = getLimbYRot(lElbowOrigin, lShoulderDispl, lShoulderOrigin, lElbowDispl, lElbowPos.z > lElbowOrigin.z ? -1 : 1);
		
		vertex = yRot * zRot * (vertex - lShoulderWorldOrigin);
		vertex = (vertex + lShoulderWorldOrigin);
		
	} 
	
	// rHand rotation
	if(baseMapColor == vec3(0.2,0.0,0.2)) {
	
		mat4 rShoulderZRot = getLimbZRot(rElbowOrigin, rShoulderDispl, rShoulderOrigin, rElbowDispl, rElbowPos.y > rElbowOrigin.y ? 1 : -1);
		mat4 rShoulderYRot = getLimbYRot(rElbowOrigin, rShoulderDispl, rShoulderOrigin, rElbowDispl, rElbowPos.z > rElbowOrigin.z ? 1 : -1);
		
		rElbowOrigin = rShoulderYRot * rShoulderZRot * (vec4(-rElbowOrigin.x, rElbowOrigin.y, rElbowOrigin.z, 1.0) - rShoulderWorldOrigin) + rShoulderWorldOrigin;
		rElbowDispl = vec4(-rElbowPos.x, rElbowPos.y, rElbowPos.z, 1.0) - rElbowOrigin;
		
		rHandOrigin = rShoulderYRot * rShoulderZRot * (vec4(-rHandOrigin.x, rHandOrigin.y, rHandOrigin.z, 1.0) - rShoulderWorldOrigin) + rShoulderWorldOrigin;
		rHandDispl = vec4(-rHandPos.x, rHandPos.y, rHandPos.z, 1.0) - rHandOrigin;
		
		mat4 rElbowZRot = getLimbZRot(rHandOrigin, rElbowDispl, rElbowOrigin, rHandDispl, rHandPos.y > rHandOrigin.y? 1 : -1);
		mat4 rElbowYRot = getLimbYRot(rHandOrigin, rElbowDispl, rElbowOrigin, rHandDispl, rHandPos.z > rHandOrigin.z? 1 : -1);
		
		vertex = rElbowYRot * rElbowZRot * (vertex - rElbowWorldOrigin);
		vertex = rShoulderYRot * rShoulderZRot * (vertex - rShoulderWorldOrigin + rElbowWorldOrigin);
		
		
		vertex = (vertex + rShoulderWorldOrigin);
		
		
	} 
	
	// lHand rotation
	if(baseMapColor == vec3(1.0,0.0,1.0)) {
	
		mat4 lShoulderZRot = getLimbZRot(lElbowOrigin, lShoulderDispl, lShoulderOrigin, lElbowDispl, lElbowPos.y > lElbowOrigin.y ? -1 : 1);
		mat4 lShoulderYRot = getLimbYRot(lElbowOrigin, lShoulderDispl, lShoulderOrigin, lElbowDispl, lElbowPos.z > lElbowOrigin.z ? -1 : 1);;
		
		lElbowOrigin = lShoulderYRot * lShoulderZRot * (vec4(-lElbowOrigin.x, lElbowOrigin.y, lElbowOrigin.z, 1.0) - lShoulderWorldOrigin) + lShoulderWorldOrigin;
		lElbowDispl = vec4(-lElbowPos.x, lElbowPos.y, lElbowPos.z, 1.0) - lElbowOrigin;
		
		lHandOrigin = lShoulderYRot * lShoulderZRot * (vec4(-lHandOrigin.x, lHandOrigin.y, lHandOrigin.z, 1.0) - lShoulderWorldOrigin) + lShoulderWorldOrigin;
		lHandDispl = vec4(-lHandPos.x, lHandPos.y, lHandPos.z, 1.0) - lHandOrigin;
		
		mat4 lElbowZRot = getLimbZRot(lHandOrigin, lElbowDispl, lElbowOrigin, lHandDispl, lHandPos.y > lHandOrigin.y ? -1 : 1);
		mat4 lElbowYRot = getLimbYRot(lHandOrigin, lElbowDispl, lElbowOrigin, lHandDispl, lHandPos.z > lHandOrigin.z ? -1 : 1);
		
		vertex = lElbowYRot * lElbowZRot * (vertex - lElbowWorldOrigin);
		vertex = lShoulderYRot * lShoulderZRot * (vertex - lShoulderWorldOrigin + lElbowWorldOrigin);
		
		vertex = (vertex + lShoulderWorldOrigin);
	} 
	
	// rKnee rotation
	if(baseMapColor == vec3(0.2,1.0,0.0)) {
		
		mat4 zRot = getLimbZRot(rKneeOrigin, rHipDispl, rHipOrigin, rKneeDispl, rKneePos.x > rKneeOrigin.x ? 1 : -1);
		mat4 xRot = getLimbXRot(rKneeOrigin, rHipDispl, rHipOrigin, rKneeDispl, rKneePos.z > rKneeOrigin.z ? -1 : 1);
		
		vertex = xRot * zRot * (vertex - rHipWorldOrigin);
		vertex = (vertex + rHipWorldOrigin);
		
	}
	
	// lKnee rotation
	if(baseMapColor == vec3(1.0,1.0,1.0)) {	
		
		mat4 zRot = getLimbZRot(lKneeOrigin, lHipDispl, lHipOrigin, lKneeDispl, lKneePos.x > lKneeOrigin.x ? 1 : -1);
		mat4 xRot = getLimbXRot(lKneeOrigin, lHipDispl, lHipOrigin, lKneeDispl, lKneePos.z > lKneeOrigin.z ? -1 : 1);
		
		vertex = xRot * zRot * (vertex - lHipWorldOrigin);
		vertex = (vertex + lHipWorldOrigin);
		
	}
	
	
	// rFoot rotation
	if(baseMapColor == vec3(1.0,0.2,0.2)) {
	
		mat4 rKneeZRot = getLimbZRot(rKneeOrigin, rHipDispl, rHipOrigin, rKneeDispl, rKneePos.x > rKneeOrigin.x ? 1 : -1);
		mat4 rKneeXRot = getLimbXRot(rKneeOrigin, rHipDispl, rHipOrigin, rKneeDispl, rKneePos.z > rKneeOrigin.z ? -1 : 1);
		
		rFootOrigin = rKneeXRot * rKneeZRot * (vec4(-rFootOrigin.x, rFootOrigin.y, rFootOrigin.z, 1.0) - rHipWorldOrigin) + rHipWorldOrigin;
		rKneeOrigin = rKneeXRot * rKneeZRot * (vec4(-rKneeOrigin.x, rKneeOrigin.y, rKneeOrigin.z, 1.0) - rHipWorldOrigin) + rHipWorldOrigin;
		
		rKneeDispl = vec4(-rKneePos.x, rKneePos.y, rKneePos.z, 1.0) - rKneeOrigin;
		rFootDispl = vec4(-rFootPos.x, rFootPos.y, rFootPos.z, 1.0) - rFootOrigin;
		
		mat4 rFootZRot = getLimbZRot(rFootOrigin, rKneeDispl, rKneeOrigin, rFootDispl, rFootPos.x > rFootOrigin.x ? -1 : 1);
		mat4 rFootXRot = getLimbXRot(rFootOrigin, rKneeDispl, rKneeOrigin, rFootDispl, rFootPos.z > rFootOrigin.z ? -1 : 1);
	
		
		vertex = rFootXRot * rFootZRot * (vertex - rKneeWorldOrigin);
		vertex = rKneeXRot * rKneeZRot * (vertex - rHipWorldOrigin + rKneeWorldOrigin);
		
		vertex = (vertex + rHipWorldOrigin);
	}
	
	
	// lFoot rotation
	if(baseMapColor == vec3(0.0,0.2,0.0)) {
	
		mat4 lKneeZRot = getLimbZRot(lKneeOrigin, lHipDispl, lHipOrigin, lKneeDispl, lKneePos.x > lKneeOrigin.x ? 1 : -1);
		mat4 lKneeXRot = getLimbXRot(lKneeOrigin, lHipDispl, lHipOrigin, lKneeDispl, lKneePos.z > lKneeOrigin.z ? -1 : 1);
		
		lFootOrigin = lKneeXRot * lKneeZRot * (vec4(-lFootOrigin.x, lFootOrigin.y, lFootOrigin.z, 1.0) - lHipWorldOrigin) + lHipWorldOrigin;
		lKneeOrigin = lKneeXRot * lKneeZRot * (vec4(-lKneeOrigin.x, lKneeOrigin.y, lKneeOrigin.z, 1.0) - lHipWorldOrigin) + lHipWorldOrigin;
		
		lKneeDispl = vec4(-lKneePos.x, lKneePos.y, lKneePos.z, 1.0) - lKneeOrigin;
		lFootDispl = vec4(-lFootPos.x, lFootPos.y, lFootPos.z, 1.0) - lFootOrigin;
		
		mat4 lFootZRot = getLimbZRot(lFootOrigin, lKneeDispl, lKneeOrigin, lFootDispl, lFootPos.x > lFootOrigin.x ? -1 : 1);
		mat4 lFootXRot = getLimbXRot(lFootOrigin, lKneeDispl, rKneeOrigin, lFootDispl, lFootPos.z > lFootOrigin.z ? -1 : 1);
	
		vertex = lFootXRot * lFootZRot * (vertex - lKneeWorldOrigin);
		vertex = lKneeXRot * lKneeZRot * (vertex - lHipWorldOrigin + lKneeWorldOrigin);
		vertex = (vertex + lHipWorldOrigin);
	}
	
	gl_Position = gl_ModelViewProjectionMatrix * vertex;    

    eyeNormal = gl_NormalMatrix * normal;
    
    eyePosition = ( gl_Vertex).xyz; 
    gl_TexCoord[0] = gl_MultiTexCoord0;  
}